﻿Ext.namespace('Ext.ux.dd');
Ext.MessageBox.buttonText.yes = "拖曳到当前位置";
Ext.MessageBox.buttonText.no = "交换";
/*
{
    xtype: "grid",
    plugins: [new Ext.ux.dd.GridDragDropRowOrder(
    {
        copy: true // false by default
        scrollable: true, // enable scrolling support (default is false)
        targetCfg: { ... } // any properties to apply to the actual DropTarget
    })]
}
.grid-row-insert-below {    border-bottom:1px solid #3366cc;}
.grid-row-insert-above {    border-top:1px solid #3366cc;} 
*/
Ext.ux.dd.GridDragDropRowOrder = function(config)
{
     if (config)
            Ext.apply(this, config);
     this.addEvents(
            "beforerowmove",
            "afterrowmove",
            "beforerowcopy",
            "afterrowcopy"
     );
     Ext.ux.dd.GridDragDropRowOrder.superclass.constructor.call(this);
};

Ext.extend(Ext.ux.dd.GridDragDropRowOrder,Ext.util.Observable,
{
    copy: false,
    scrollable: false,
 
    init : function (grid)
    {
        this.grid = grid;
        grid.enableDragDrop = true;
        grid.on({
            render: { fn: this.onGridRender, scope: this, single: true }
        });
    },

    onGridRender : function (grid)
    {
        var self = this;
        this.target = new Ext.dd.DropTarget(grid.getEl(),
        {
            ddGroup: grid.ddGroup || 'GridDD',
            grid: grid,
            gridDropTarget: this,
            
            notifyDrop: function(dd, e, data)
            {
                // determine the row
                var t = Ext.lib.Event.getTarget(e);
                var rindex = this.grid.getView().findRowIndex(t);
                if (rindex === false || rindex == data.rowIndex)
                {
                    return false;
                }
                // fire the before move/copy event
                if (this.gridDropTarget.fireEvent(self.copy ? 'beforerowcopy' : 'beforerowmove', this.gridDropTarget, data.rowIndex, rindex, data.selections, 123) === false)
                {
                    return false;
                }
                // update the store
                var ds = this.grid.getStore();

                // Changes for multiselction by Spirit
                var selections = new Array();
                var keys = ds.data.keys;
                for (var key in keys)
                {
                    for (var i = 0; i < data.selections.length; i++)
                    {
                        if (keys[key] == data.selections[i].id)
                        {
                            // Exit to prevent drop of selected records on itself.
                            if (rindex == key)
                            {
                                return false;
                            }
                            selections.push(data.selections[i]);
                        }
                    }
                }
                var isMove = true;       // is move?
                Ext.MessageBox.show({
                       title:'操作提示',
                       msg: '请选择',
                       buttons: Ext.MessageBox.YESNOCANCEL,
                       animEl: this.grid.getEl(),
                       icon: Ext.MessageBox.QUESTION,
                       scope : this,    
                       fn:function(text){
                           if(text === 'yes')
                           {
                                 // fix rowindex based on before/after move
                                if (rindex > data.rowIndex && this.rowPosition < 0)
                                {
                                    rindex--;
                                }
                                if (rindex < data.rowIndex && this.rowPosition > 0)
                                {
                                    rindex++;
                                }
                                // fix rowindex for multiselection
                                if (rindex > data.rowIndex && data.selections.length > 1)
                                {
                                    rindex = rindex - (data.selections.length - 1);
                                }
                                // we tried to move this node before the next sibling, we stay in place
                                if (rindex == data.rowIndex)
                                {
                                    return false;
                                }
                                if (!self.copy)
                                {
                                    for (var i = 0; i < data.selections.length; i++)
                                    {
                                        ds.remove(ds.getById(data.selections[i].id));
                                    }
                                }
                                for (var i = selections.length - 1; i >= 0; i--)
                                {
                                    var insertIndex = rindex;
                                    ds.insert(insertIndex, selections[i]);
                                }
                                // re-select the row(s)
                                var sm = this.grid.getSelectionModel();
                                if (sm)
                                {
                                    sm.selectRecords(data.selections);
                                }
                                isMove = true; 
                                
                           }
                           else if(text === "no")
                           {
                                var oldEl = ds.getById(data.selections[0].id);
                                var newEl = ds.getAt(rindex);
                                ds.remove(oldEl);
                                ds.insert(rindex, oldEl);
                                ds.remove(newEl);
                                ds.insert(data.rowIndex,newEl);
                                var sm = this.grid.getSelectionModel();
                                if (sm)
                                {
                                    sm.selectRecords(data.selections);
                                }
                                isMove = false; 
                           }
                           else
                           {
                                 // Remove drag lines. The 'if' condition prevents null error when drop occurs without dragging out of the selection area
                                if (this.currentRowEl)
                                {
                                    this.currentRowEl.removeClass('grid-row-insert-below');
                                    this.currentRowEl.removeClass('grid-row-insert-above');
                                }
                                return false;
                           } 
                           (function(){
                                this.grid.store.fireEvent('datachanged', this.grid.store);
                                // fire the after move/copy event
                                this.gridDropTarget.fireEvent(self.copy ? 'afterrowcopy' : 'afterrowmove', this.gridDropTarget, data.rowIndex, rindex, data.selections,isMove);        
                            }).defer(50,this);
                      }
                 });
                return true;
            },

            notifyOver: function(dd, e, data)
            {
                if(data.selections.length === 0)
                    return this.dropNotAllowed;
                var t = Ext.lib.Event.getTarget(e);
                var rindex = this.grid.getView().findRowIndex(t);

                // Similar to the code in notifyDrop. Filters for selected rows and quits function if any one row matches the current selected row.
                var ds = this.grid.getStore();
                var keys = ds.data.keys;
                for (var key in keys)
                {
                    for (var i = 0; i < data.selections.length; i++)
                    {
                        if (keys[key] == data.selections[i].id)
                        {
                            if (rindex == key)
                            {
                                if (this.currentRowEl)
                                {
                                    this.currentRowEl.removeClass('grid-row-insert-below');
                                    this.currentRowEl.removeClass('grid-row-insert-above');
                                }
                                return this.dropNotAllowed;
                            }
                        }
                    }
                }

                // If on first row, remove upper line. Prevents negative index error as a result of rindex going negative.
                if (rindex < 0 || rindex === false)
                {
                    this.currentRowEl.removeClass('grid-row-insert-above');
                    return this.dropNotAllowed;
                }

                try
                {
                    var currentRow = this.grid.getView().getRow(rindex);
                    // Find position of row relative to page (adjusting for grid's scroll position)
                    var resolvedRow = new Ext.Element(currentRow).getY() - this.grid.getView().scroller.dom.scrollTop;
                    var rowHeight = currentRow.offsetHeight;

                    // Cursor relative to a row. -ve value implies cursor is above the row's middle and +ve value implues cursor is below the row's middle.
                    this.rowPosition = e.getPageY() - resolvedRow - (rowHeight/2);

                    // Clear drag line.
                    if (this.currentRowEl)
                    {
                        this.currentRowEl.removeClass('grid-row-insert-below');
                        this.currentRowEl.removeClass('grid-row-insert-above');
                    }

                    if (this.rowPosition > 0)
                    {
                        // If the pointer is on the bottom half of the row.
                        this.currentRowEl = new Ext.Element(currentRow);
                        this.currentRowEl.addClass('grid-row-insert-below');
                    }
                    else
                    {
                        // If the pointer is on the top half of the row.
                        if (rindex - 1 >= 0)
                        {
                            var previousRow = this.grid.getView().getRow(rindex - 1);
                            this.currentRowEl = new Ext.Element(previousRow);
                            this.currentRowEl.addClass('grid-row-insert-below');
                        }
                        else
                        {
                            // If the pointer is on the top half of the first row.
                            this.currentRowEl.addClass('grid-row-insert-above');
                        }
                    }
                }
                catch (err)
                {
                    //console.warn(err);
                    rindex = false;
                    alert(err);
                }
                return (rindex === false)? this.dropNotAllowed : this.dropAllowed;
            },

            notifyOut: function(dd, e, data)
            {
                // Remove drag lines when pointer leaves the gridView.
                if (this.currentRowEl)
                {
                    this.currentRowEl.removeClass('grid-row-insert-above');
                    this.currentRowEl.removeClass('grid-row-insert-below');
                }
            }
        });

        if (this.targetCfg)
        {
            Ext.apply(this.target, this.targetCfg);
        }

        if (this.scrollable)
        {
            Ext.dd.ScrollManager.register(grid.getView().getEditorParent());
            grid.on({
                beforedestroy: this.onBeforeDestroy,
                scope: this,
                single: true
            });
        }
    },

    getTarget: function()
    {
        return this.target;
    },

    getGrid: function()
    {
        return this.grid;
    },

    getCopy: function()
    {
        return this.copy ? true : false;
    },

    setCopy: function(b)
    {
        this.copy = b ? true : false;
    },

    onBeforeDestroy : function (grid)
    {
        // if we previously registered with the scroll manager, unregister
        // it (if we don't it will lead to problems in IE)
        Ext.dd.ScrollManager.unregister(grid.getView().getEditorParent());
    }
});

/*
Perhaps it should be specified in the documentation but Grid's CheckboxSelectionModel and Drag and Drop are not compatible. 

Both of them are fighting to process events on handleMouseDown. At one point I had to write up an override to get both of them working together. Try this:

*/
Ext.grid.CheckboxSelectionModel.override({
    handleMouseDown : Ext.emptyFn
}
);
Ext.grid.RowSelectionModel.override({
    initEvents : function() {
        if(!this.grid.enableDragDrop && !this.grid.enableDrag){
            this.grid.on("rowmousedown", this.handleMouseDown, this);
        }
        else{
            // allow click to work like normal 
            this.grid.on("rowclick", function(grid, rowIndex, e) {
                var target = e.getTarget(); if(target.className !== 'x-grid3-row-checker' && e.button === 0 && !e.shiftKey && !e.ctrlKey) {
                    this.selectRow(rowIndex, false); grid.view.focusRow(rowIndex);
                }
            }
            , this);
        }
        this.rowNav = new Ext.KeyNav(this.grid.getGridEl(), {
            "up" : function(e){
                if(!e.shiftKey){
                    this.selectPrevious(e.shiftKey);
                }
                else if(this.last !== false && this.lastActive !== false){
                    var last = this.last; this.selectRange(this.last, this.lastActive-1); this.grid.getView().focusRow(this.lastActive); if(last !== false){
                        this.last = last;
                    }
                }
                else{
                    this.selectFirstRow();
                }
             }
            , "down" : function(e){
                if(!e.shiftKey){
                    this.selectNext(e.shiftKey);
                }
                else if(this.last !== false && this.lastActive !== false){
                    var last = this.last; this.selectRange(this.last, this.lastActive+1); this.grid.getView().focusRow(this.lastActive); if(last !== false){
                        this.last = last;
                    }
                }
                else{
                    this.selectFirstRow();
                }
            }
            , 
            scope: this
        }
        ); 
        var view = this.grid.view; view.on("refresh", this.onRefresh, this); view.on("rowupdated", this.onRowUpdated, this); view.on("rowremoved", this.onRemove, this);
    }
}
); 
Ext.grid.GridDragZone.override({
    onInitDrag : function(e){
        var data = this.dragData;
        this.ddel.innerHTML = data.rowElement.innerHTML;
        this.proxy.update(this.ddel);
        // fire start drag?
    },
    getDragData : function(e){
        var t = Ext.lib.Event.getTarget(e);
        var rowIndex = this.view.findRowIndex(t);
        var target = Ext.get(e.getTarget());
        if(rowIndex !== false){
            var sm = this.grid.selModel;
            if(!sm.isSelected(rowIndex) || e.hasModifier()){
                sm.handleMouseDown(this.grid, rowIndex, e);
            }
            return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections(),rowElement:this.view.getRow(rowIndex),item:target};
        }
        return false;
    },
    getRepairXY: function(e, data) {
        data.item.highlight('#e8edff');
        return data.item.getXY();
    }
});  